/**
 * Path.cpp
 * Coyright (c) 2009 Xiaofeng Gu. All Rights Reserved.
 * Author : Xiaofeng Gu
 *
 * Creation Data : 2009/06/11
 */

#include "stdafx.h"
#include "Path.h"
#include <math.h>

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

CTransPath::CTransPath()
: gradRatio(1.0)
{
}

CTransPath::~CTransPath()
{
}

bool CTransPath::IsLinearPath(CVec& startDir, CVec& endDir)
{
	CVec V = startDir^endDir;
	if (fabs(V.Length()) < DELTA)
	{
		return true;
	}
	else
	{
		return false;
	}

	return true;
}

void CTransPath::Create()
{
	m_oParts.clear();

	double S = CalculateRange();

	if (fabs(gradRatio - 1) < DELTA)
	{
		long n = m_lItemCount - 1;
		double dS = S / n;

		for (long l = 1; l <= n; l ++)
		{
			m_oParts.push_back(dS);
		}
	}
	else
	{
	}

	/*long n = m_lItemCount - 1;
	double dS = S / (n * (n + 1) / 2);
	m_oParts.push_back(dS);

	double dGradS = dS;
	for (long l = 1; l < n; l ++)
	{
		dGradS = dGradS * gradRatio;
		m_oParts.push_back(dGradS);
	}*/
}


////////////////////////////////////////
// CLinearPath
////////////////////////////////////////
void CLinearPath::Create()
{
	__super::Create();

	CVec pathPt = start;
	m_oPath.push_back(pathPt[0]);
	m_oPath.push_back(pathPt[1]);
	m_oPath.push_back(pathPt[2]);

	CVec V = end - start;
	V.Identify();
	for (Parts::iterator it = m_oParts.begin();
		it != m_oParts.end(); it ++)
	{
		pathPt = V*(*it) + pathPt;

		m_oPath.push_back(pathPt[0]);
		m_oPath.push_back(pathPt[1]);
		m_oPath.push_back(pathPt[2]);
	}
}

double CLinearPath::CalculateRange()
{
	CVec V = end - start;
	return V.Length();
}


////////////////////////////////////////
// CCirclePath
////////////////////////////////////////
double CCirclePath::CalculateRange()
{
	CVec V = start - center;
	CVec V2 = end - center;

	return V.CrossAngle(V2);
}

void CCirclePath::Create()
{
	__super::Create();

	CalculateCenter();

	CVec V = start - center;
	CVec V2 = end - center;
	CVec rot = V ^ V2;

	CVec pathPt = start;
	m_oPath.push_back(pathPt[0]);
	m_oPath.push_back(pathPt[1]);
	m_oPath.push_back(pathPt[2]);

	for (Parts::iterator it = m_oParts.begin();
		it != m_oParts.end(); it ++)
	{
		V.RotateBy(rot, *it);
		pathPt = V + center;

		m_oPath.push_back(pathPt[0]);
		m_oPath.push_back(pathPt[1]);
		m_oPath.push_back(pathPt[2]);
	}
}

void CCirclePath::CalculateCenter()
{
	CVec SE = end - start;
	CVec N = tangentStart ^ tangentEnd;
	CVec v = N ^ tangentStart;
	v.Identify();
	CVec u = N ^ tangentEnd;
	u.Identify();
	CVec p = start;
	CVec q = end;


	// p + v * s = q + u * t
	// B = [v0 uo; v1 u1; v2 u2]
	// C = [q0 - p0; q1 - p1; q2 - p2]
	// B * [s; t] = C

	// B = [v0 u0; v1 u1];
	// C = [q0 - p0; q1 - p1];
	// [s; t] = B^(-1) C

	// [s; t] = {[u1 -u0; -v1 v0]/(v0*u1 - u0*v1)} [q0 - p0; q1 - p1]
	// [s; t] = {[u2 -u0; -v2 v0]/(v0*u2 - u0*v2)} [q0 - p0; q2 - p2]
	// [s; t] = {[u2 -u1; -v2 v1]/(v1*u2 - u1*v2)} [q1 - p1; q2 - p2]
	
	if (SE.Length() > DELTA)
	{
		double s = 0;

		double A = v[0]*u[1] - u[0]*v[1];
		if (fabs(A) > DELTA)
		{
			s = u[1]*(q[0] - p[0]) - u[0]*(q[1] - p[1]) / A;
			return;
		}

		double B = v[0]*u[2] - u[0]*v[2];
		if (fabs(B) > DELTA)
		{
			s = u[2]*(q[0] - p[0]) - u[0]*(q[2] - p[2]) / B;
			return;
		}

		double C = v[1]*u[2] - u[1]*v[2];
		if (fabs(C) > DELTA)
		{
			s = u[2]*(q[1] - p[1]) - u[1]*(q[2] - p[2]) / C;
			return;
		}

		center = p + v * s;
	}
}